package com.hk.factory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.hk.config.Bean;
import com.hk.config.Property;
import com.hk.config.parse.ConfigManager;
import com.hk.utils.BeanUtils;

public class ClassPathXmlApplicationContext implements BeanFactory {

	//容器context 存储着所有的 singleton bean 
	Map<String,Object> context = new HashMap<>();
	Map<String, Bean> config;
	public ClassPathXmlApplicationContext(String url) {
		 config = ConfigManager.getConfig(url);
		if(config!=null) {
			for(Entry<String,Bean> entry : config.entrySet()) {
				String beanName = entry.getKey();
				Bean bean = entry.getValue();
				Object objBean = context.get(beanName);
				//singleton 模式，如果已经存在，就么有必要再去创建。
				//不存在该bean ，进行创建
					if(objBean == null && bean.getScope().equals("singleton")) {
						Object obj = createAndInitBean(bean);
						context.put(beanName, obj);
					}
				
			}
		}
	}
	
	private Object createAndInitBean(Bean bean) {
		// TODO Auto-generated method stub
		String className = bean.getClassName();
		Class<?> clazz = null;
		Object beanInstance=null;
		try {
			clazz = Class.forName(className);
			beanInstance = clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("没有找到该类，请检查xml "+ className);
		}
		//将属性注入bean
		//分两种情况 
		//1.简单的类型注入
		List<Property> properties = bean.getProperties();
		for(Property prop : properties) {
			String name = prop.getName();
			//(2)调用BeanUtils包下面的方法
			String value = prop.getValue();
			String ref = prop.getRef();
			if(value!=null) {
				Map<String,String> paramMap = new HashMap<>();
				paramMap.put(name, value);
				try {
					org.apache.commons.beanutils.BeanUtils.populate(beanInstance,paramMap);
				} catch (Exception e) {
					throw new RuntimeException("请检查"+name+"属性");
				}
			}
			if(prop.getRef()!=null) {
				Method setMethod = BeanUtils.getSetMethod(beanInstance,name);
				Object param = null;
			//2.ref的bean类型注入
			//先在容器中查看该bean是否存在，如果不存在，应该先创建
			Object existBean = context.get(prop.getRef());
			if(existBean == null) {
				existBean = createAndInitBean(config.get(prop.getRef()));
				//将创建好的Bean放入容器中
				if(config.get(prop.getRef()).getScope().equals("singleton"))
						context.put(prop.getRef(),(Bean) existBean);
			}
			param = existBean;
			try {
				setMethod.invoke(beanInstance, param);
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				e.printStackTrace();
				throw new RuntimeException("Bean的属性"+name+"没有对应的set方法："+className);
			}
		}
				
				
//			//(1)自己动手写的属性注入，没有做类型转换
//			Method setMethod = BeanUtils.getSetMethod(beanInstance,name);
//			Object param = null;
//			if(prop.getValue()!=null) {
//				String value = prop.getValue();
//				param = value;
//			}
//			if(prop.getRef()!=null) {
//				//2.ref的bean类型注入
//				//先在容器中查看该bean是否存在，如果不存在，应该先创建
//				Object existBean = context.get(prop.getRef());
//				if(existBean == null) {
//					existBean = createAndInitBean(config.get(prop.getRef()));
//					//将创建好的Bean放入容器中
//					if(config.get(prop.getRef()).getScope().equals("singleton"))
//						context.put(prop.getRef(),(Bean) existBean);
//				}
//				param = existBean;
//			}
//			try {
//				setMethod.invoke(beanInstance, param);
//			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
//				e.printStackTrace();
//				throw new RuntimeException("Bean的属性"+name+"没有对应的set方法："+className);
//			}
		}
		return beanInstance;
	}


	@Override
	public Object getBean(String beanName) {
		//context容器中只有单例bean
		Object obj = context.get(beanName);
		//这是scope == prototype,直接创建一个bean
		if(obj == null)
			obj = createAndInitBean(config.get(beanName));
		return obj;
	}
	
}
